#ifndef OBJECT_H
#define OBJECT_H

#include <string>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
#include <time.h>
using namespace std;

class var;

class Object
{
public:
	int c;
	inline Object() : c(1) {}
	inline Object(int n) : c(n) {}

	virtual var		operator()();

	virtual void		push(var o);
	virtual var			pop();
    virtual const char* toString();
	virtual bool		toBool();

	virtual var			length();
	virtual bool	    isEmpty();
	virtual var			draw();
	virtual var			onDraw();
//code

};

typedef var (*delegate)(...);

#define INLINE
template <class T>
class ref;
typedef long long integer;
typedef void New;

class var
{
public:

	class Array : public Object, public vector<var>
	{
	public:
		inline Array() {}
		inline Array(long long n) : vector<var>((size_type)n) {}
		inline Array(double n) : vector<var>((size_type)n) {}
		inline Array(var n) : vector<var>((size_type)n.i) {}

		void    push(var o) { push_back (o); }
		var		pop() 
		{ 
			var last = back();
			pop_back();
			return last;
		}
		var  	length() { return (long long)size(); }
		bool    isEmpty() { return empty(); }

		inline Array* push_init(var o)
		{
			push_back(o);
			return this;
		}

		const char* toString() { return "Array"; }
	};

	class Map : public Object, public map<string,var>
	{
	public:
		inline Map() {}
		inline Map* init(const char* s, var a)
		{
			map<string,var>::operator[](s) = a;
			return this;
		}

		const char* toString() { return "Map"; }
	};

	class String : public Object, public string
	{
	public:
		String();
		String(const char* string);
		String(double );
		String(long long );
		String(char);
		String(const var& str);
		String(const string& str);
		const char* toString();
		var		length();
	};

	static Object* null;

	enum VarType 
	{ 
		Int,
		Float,
		Obj = 3	
	};

	long long i;
	double f;
	Object* o;
	short t;

	inline var() : o(null), t(Obj) { }
	//inline var(integer _i, double _f, Object* _o, short _t) : i(_i), f(_f), o(_o), t(_t) { inc(); }
	inline var(const var& v) : i(v.i) , f(v.f), o(v.o), t(v.t) { inc(); }
	inline var(Object* n) : o(n), t(Obj) { inc(); }
	inline var(New* n) : o((Object*)n), t(Obj) { }
	inline var(double n) : i((integer)n), f(n), o(null), t(Float) { }
	inline var(integer n) : i(n), f((double)n), o(null), t(Int) {  }
	inline var(const char* n) : o(new String(n)), t(Obj) { inc(); }
	inline var(bool n) : i(n), f(n), o(null), t(Int) {  }
	inline var(const string& s) : o(new String(s)), t(Obj) { inc(); }
	inline var(char n) : o(new String(n)), t(Obj) { inc(); }
	template <class T>
	inline var(const ref<T>& r) : o(r.o), t(Obj) { inc(); }
	inline ~var() { dec(); }

	inline void operator=(double n) { dec(); i = (integer)n; f = n; t = Float; }
	inline void operator=(integer n) { dec(); i = n; f = (double)n; t = Int; }
	inline void operator=(bool n) { dec(); i = n; f = n; t = Int; }
	inline void operator=(Object* n) { dec(); o = n; t = Obj; inc(); }
	inline void operator=(New* n) { dec(); o = (Object*)n; t = Obj; }
	inline void operator=(const var& v) { dec(); i = v.i; f = v.f; o = v.o; t = v.t; inc(); }
	inline void operator=(const char* v) { dec(); o = new String(v); t = Obj; inc(); }
	inline void operator=(const string& s) { dec(); o = new String(s); t = Obj;  inc(); }
	template <class T>
	inline void operator=(const ref<T>& v) { dec(); o = v.o; t = Obj; inc(); }
	inline Object* operator->() const { return o; }
	inline Object& operator*() const { return *o; }

	inline void dec() { if (o != null && --(o->c) == 0) delete o;}
	inline void inc() { o->c++; }

	inline void operator++() { ++i; ++f; }
	inline void operator--() { --i; --f; }
	inline integer operator-() const { return -i; } 

	// assign var&
	inline void operator+=(const var& v) { i += v.i; f += v.f; t |= v.t; }
	inline void operator-=(const var& v) { i -= v.i; f -= v.f; t |= v.t; }
	inline void operator/=(const var& v) { i /= v.i; f /= v.f; t |= v.t; }
	inline void operator*=(const var& v) { i *= v.i; f *= v.f; t |= v.t; }
	inline void operator%=(const var& v) { i %= v.i; f = (double)i; t |= v.t; }
	// assign double
	inline void operator+=(double v) { i += (long long)v; f += v; t |= Float; }
	inline void operator-=(double v) { i -= (long long)v; f -= v; t |= Float; }
	inline void operator/=(double v) { i /= (long long)v; f /= v; t |= Float; }
	inline void operator*=(double v) { i *= (long long)v; f *= v; t |= Float; }
	inline void operator%=(double v) { i %= (long long)v; f = (double)i; t |= Float; }
	// assign long long
	inline void operator+=(long long v) { i += v; f += v; }
	inline void operator-=(long long v) { i -= v; f -= v; }
	inline void operator/=(long long v) { i /= v; f /= v; }
	inline void operator*=(long long v) { i *= v; f *= v; }
	inline void operator%=(long long v) { i %= v; f = (double)i; }

	// ops var&
	inline integer operator+(const var& v) const { return i + v.i; }
	inline integer operator-(const var& v) const { return i - v.i; }
	inline integer operator/(const var& v) const { return i / v.i; }
	inline integer operator*(const var& v) const { return i * v.i; }
	inline integer operator%(const var& v) const { return i % v.i; }
	// ops double
	inline integer operator+( double v) const { return i + v; }
	inline integer operator-( double v) const { return i - v; }
	inline integer operator/( double v) const { return i / v; }
	inline integer operator*( double v) const { return i * v; }
	inline integer operator%( double v) const { return i % (integer)v; }
	// ops long long 
	inline integer operator+( long long v) const { return i + v; }
	inline integer operator-( long long v) const { return i - v; }
	inline integer operator/( long long v) const { return i / v; }
	inline integer operator*( long long v) const { return i * v; }
	inline integer operator%( long long v) const { return i % v; }

	// bit ops long long 
	inline integer operator|( long long v) const { return i | v; }
	inline integer operator&( long long v) const { return i & v; }
	inline integer operator<<( long long v) const { return i << v; }
	inline integer operator>>( long long v) const { return i >> v; }
	inline integer operator^( long long v) const { return i ^ v; }

	// bit ops var
	inline integer operator|( const var& v) const { return i | v.i; }
	inline integer operator&( const var& v) const { return i & v.i; }
	inline integer operator<<( const var& v) const { return i << v.i; }
	inline integer operator>>( const var& v) const { return i >> v.i; }
	inline integer operator^( const var& v) const { return i ^ v.i; }

	// assign bit ops long long 
	inline void operator|=( long long v) { i |= v; f = (double)i; t = Int; }
	inline void operator&=( long long v) { i &= v; f = (double)i; t = Int; }
	inline void operator<<=( long long v) {i <<= v; f = (double)i; t = Int; }
	inline void operator>>=( long long v) { i >>= v; f = (double)i; t = Int; }
	inline void operator^=( long long v) { i ^= v; f = (double)i; t = Int; }

	// assign bit ops var
	inline void operator|=( const var& v) { i |= v.i; f = (double)i; t = Int; }
	inline void operator&=( const var& v) { i &= v.i; f = (double)i; t = Int; }
	inline void operator<<=( const var& v) { i <<= v.i; f = (double)i; t = Int; }
	inline void operator>>=( const var& v) { i >>= v.i; f = (double)i; t = Int; }
	inline void operator^=( const var& v) { i ^= v.i; f = (double)i; t = Int; }


	inline integer operator~() const { return ~i; }

	inline bool	operator&&(const var& v) const { return i && v.i; }
	inline bool	operator||(const var& v) const { return i || v.i; }
	inline bool	operator==(const var& v) const { return i == v.i && f == v.f && o == v.o; }
	inline bool	operator!=(const var& v) const { return i != v.i && f != v.f && o != v.o; }
	inline bool	operator!() const { return !i; }

	inline bool	operator&&(bool v) const { return i && v; } 
	inline bool	operator||(bool v) const { return i || v; } 
	inline bool	operator==(bool v) const { return i ? true == v : false == v; } 
	inline bool	operator!=(bool v) const { return i ? false == v : true == v; } 

	inline bool	operator==(const Object* v) const { return o == v; } 
	inline bool	operator!=(const Object* v) const { return o != v; } 

	// compare with double
	inline bool operator ==(double v) const { return f == v; } 
	inline bool operator !=(double v) const { return f != v; } 
	inline bool operator <(double v) const { return f < v; } 
	inline bool operator >(double v) const { return f > v; } 
	inline bool operator <=(double v) const { return f <= v; } 
	inline bool operator >=(double v) const { return f >= v; } 

	// compare with long long
	inline bool operator==(integer v) const { return i == v; } 
	inline bool operator!=(integer v) const { return i != v; } 
	inline bool operator<(integer v) const { return i < v; } 
	inline bool operator>(integer v) const { return i > v; } 
	inline bool operator<=(integer v) const { return i <= v; } 
	inline bool operator>=(integer v) const { return i >= v; } 


	// compare with var
	inline bool operator<(var& v) const { return !(t|v.t) ? i < v.i : f < v.f; }
	inline bool operator>(var& v) const { return !(t|v.t) ? i < v.i : f < v.f; }
	inline bool operator<=(var& v) const { return !(t|v.t) ? i < v.i : f < v.f; }
	inline bool operator>=(var& v) const { return !(t|v.t) ? i < v.i : f < v.f; }

	// compare with double
	friend inline bool operator ==(double v, const var& o) { return v == o.f; } 
	friend inline bool operator !=(double v, const var& o) { return v != o.f; } 
	friend inline bool operator <(double v, const var& o) { return v < o.f; } 
	friend inline bool operator >(double v, const var& o) { return v > o.f; } 
	friend inline bool operator <=(double v, const var& o) {  return v <= o.f; } 
	friend inline bool operator >=(double v, const var& o) { return v >= o.f; } 

	// compare with long long
	friend inline bool operator==(long long v, const var& o)  { return v == o.i; } 
	friend inline bool operator!=(long long v, const var& o)  { return v != o.i; } 
	friend inline bool operator<(long long v, const var& o)  { return v < o.i; } 
	friend inline bool operator>(long long v, const var& o)  { return v > o.i; } 
	friend inline bool operator<=(long long v, const var& o)  { return v <= o.i; } 
	friend inline bool operator>=(long long v, const var& o)  { return v >= o.i; } 

	inline var&	operator[](long long v) const { return static_cast<Array*>(o)->at((unsigned)v); }
	inline var&	operator[](double v) const { return static_cast<Array*>(o)->at((unsigned)v); }
	inline var&	operator[](var& v) const { return static_cast<Array*>(o)->at((unsigned)v.i); }

	friend inline integer operator+(double n, const var& v) { return n + v.i; }
	friend inline integer operator-(double n, const var& v) { return n - v.i; }
	friend inline integer operator/(double n, const var& v) { return n / v.i; }
	friend inline integer operator*(double n, const var& v) { return n * v.i; }
	friend inline integer operator%(double n, const var& v) { return (long long)n % v.i; }

	friend inline integer operator+(long long n, const var& v) { return n + v.i; } 
	friend inline integer operator-(long long n, const var& v) { return n - v.i; }
	friend inline integer operator/(long long n, const var& v) { return n / v.i; }
	friend inline integer operator*(long long n, const var& v) { return n * v.i; }
	friend inline integer operator%(long long n, const var& v) { return n % v.i; }

	friend inline var& _map_of(const var& v, const var& s) { return static_cast<Map&>(*v.o)[s.toString()]; }
	friend inline var& _map_of(const var& v, const char* s) { return static_cast<Map&>(*v.o)[s]; }

	friend inline void operator-=(double& a, const var& o) { a -= o.f; }
	friend inline void operator+=(double& a, const var& o) { a += o.f; }
	friend inline void operator/=(double& a, const var& o) { a /= o.f; }
	friend inline void operator*=(double& a, const var& o) { a *= o.f; }

	friend inline void operator-=(long long& a, const var& o) { a -= o.i; }
	friend inline void operator+=(long long& a, const var& o) { a += o.i; }
	friend inline void operator/=(long long& a, const var& o) { a /= o.i; }
	friend inline void operator*=(long long& a, const var& o) { a *= o.i; }
	friend inline void operator%=(long long& a, const var& o) { a %= o.i; }

	inline operator double() const { return f; }
	inline operator integer() const { return i; }
	//inline operator string() const { return toString(); }
	string toString() const;
	inline integer I() const { return i; }
	inline double F() const { return f; }

};

typedef var::Array Array;
typedef var::String String;
typedef var::Map Map;


inline bool _str_eq(const char* s, const var& o) { return s == o.toString(); }
inline bool _str_neq(const char* s, const var& o) { return s != o.toString(); }
	
inline bool _str_eq(const var& s, const var& o) { return s.toString() == o.toString(); }
inline bool _str_neq(const var& s, const var& o) { return s.toString() != o.toString(); }
	
inline bool _str_eq(const var& s, const char* o) { return s.toString() == o; }
inline bool _str_neq(const var& s, const char* o) { return s.toString() != o; }

inline bool _str_eq(const char* s, const char* ss) { return strcmp(s,ss) == 0; }
inline bool _str_neq(const char* s, const char* ss) { return strcmp(s,ss) != 0; }

inline string _cat(string o, const char* string) { return o += string; }
inline string _cat(string o, double v) { ostringstream s; s << o << v; return s.str(); }
inline string _cat(string o, long long v) { ostringstream s; s << o << v; return s.str(); } 
inline string _cat(string o, const string& v) { return o += v; }
inline string _cat(string s, const var& o) { return s += o.toString(); }

inline string _cat(const char* s, const string& o) { string r(s); return r += o; }
inline string _cat(long long v, const string& o) { ostringstream s; s << v << o; return s.str(); }
inline string _cat(double v, const string& o) { ostringstream s; s << v << o; return s.str(); }
inline string _cat(double v, const char* o) { ostringstream s; s << v << o; return s.str(); }
inline string _cat(long long v, const char* o) { ostringstream s; s << v << o; return s.str(); }
inline string _cat(const char* o, double v) { ostringstream s; s << o << v; return s.str(); }
inline string _cat(const char* o, long long v) { ostringstream s; s << o << v; return s.str(); }

inline string _cat(const var& o, const string& s) { return o.toString() += s; }
inline string _cat(const var& o, const char* string) { return o.toString() += string; }
inline string _cat(const var& o, double v) { ostringstream s; s << o.toString() << v; return s.str(); }
inline string _cat(const var& o, long long v) { ostringstream s; s << o.toString() << v; return s.str(); } 
inline string _cat(const var& o, const var& v) { return o.toString() += v.toString(); }
inline string _cat(const char* s, const var& o) { string r(s); return r += o.toString(); }
inline string _cat(long long v, const var& o) { ostringstream s; s << v << o.toString(); return s.str(); }

// ops var&

inline double _p(const var& l, const var& v) { return l.f + v.f; }
inline double _m(const var& l, const var& v) { return l.f - v.f; }
inline double _d(const var& l, const var& v) { return l.f / v.f; }
inline double _x(const var& l, const var& v) { return l.f * v.f; }

// ops
template <typename A>
inline double _p(const var& l, A v) { return l.f + v; }
template <typename A>
inline double _m(const var& l, A v) { return l.f - v; }
template <typename A>
inline double _d(const var& l, A v) { return l.f / v; }
template <typename A>
inline double _x(const var& l, A v) { return l.f * v; }

template <typename A>
inline double _p(A n, const var& v) { return n + v.f; }
template <typename A>
inline double _m(A n, const var& v) { return n - v.f; }
template <typename A>
inline double _d(A n, const var& v) { return n / v.f; }
template <typename A>
inline double _x(A n, const var& v) { return n * v.f; }

template <typename A, typename B>
inline double _p(A n, B v) { return (double)n + (double)v; }
template <typename A, typename B>
inline double _m(A n, B v) { return (double)n - (double)v; }
template <typename A, typename B>
inline double _d(A n, B v) { return (double)n / (double)v; }
template <typename A, typename B>
inline double _x(A n, B v) { return (double)n * (double)v; }

template <class T>
class ref
{
public:
	T* o;
	inline ref(T* v) : o(v) {inc();}
	inline ref(New* v) : o((T*)v) {}
	inline ref(const ref& r) : o(r.o) { inc(); }
	inline ~ref() { dec(); }
	inline void operator=(T* v) { dec(); o = v; inc(); }
	inline void operator=(New* v) { dec(); o = (T*)v; }
	inline void operator=(const ref& r) { dec(); o = r.o; inc(); }

	inline void dec() { if (o != var::null && --(o->c) == 0) delete o;}
	inline void inc() { ++o->c; }
	inline T* operator->() const { return o; }
	inline T& operator*() const { return *o; }

	//inline operator var() const { return var(o); }
};
#endif
